#include <stdio.h>
#include <sys/time.h>
#include <sched.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <error.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>          // 系统调用相关的函数 close()
#include <string.h>          // strcpy, memset(), and memcpy()
#include <sys/types.h>       // 包含了一些基本的系统数据类型 uint8_t、uint16_t 和 uint32_t
#include <sys/socket.h>      // 与套接字相关的函数和数据结构
#include <netinet/in.h>      // 与 Internet 协议族相关的数据结构
#include <netinet/ip.h>      // IP 协议头部的数据结构
#include <netinet/ip_icmp.h> // 定义了 ICMP 协议头部的数据结构
#include <arpa/inet.h>       // 定DEAN义了一些 IP 地址转换函数
#include <sys/ioctl.h>       // 进DEAN行输入/输出控制的函数和相关宏
#include <bits/ioctls.h>     // 用于 ioctl() 函数的参数
#include <net/if.h>          // 处理网络接口相关的函数和数据结构
#include <linux/if_ether.h>  // 帧格式 以太网帧的一些常量
#include <linux/if_packet.h> // 用于与套接字相关联的网络接口的数据结构 struct sockaddr_ll
#include <net/ethernet.h>    // 以太网帧的数据结构
#include <errno.h>           // errno, perror()
#include "tsmp.h"
#include "ptp.h"

#define PACKET_LEN 128 // 数据包的最大长度为 2048 字节
#define NET_INIT "ens33"


struct sockaddr_ll device_rec;
struct ifreq req;

int create_socket_handle(const char *net_interface)
{
    int fd;
    int ret = 0;

    if (NULL == net_interface)
    {
        perror("pcap_lookupdev");
        return -1;
    }

    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (fd < 0)
    {
        perror("socket fail\n");
        return -1;
    }

    // 指定网卡名称
    // strcpy(req.ifr_name, net_interface);
    strncpy(req.ifr_name, net_interface, IFNAMSIZ);

    if (-1 == ioctl(fd, SIOCGIFINDEX, &req))
    {
        printf("ioctl error!\n");
        close(fd);
        return -1;
    }

    /*将网络接口赋值给原始套接字地址结构*/
    bzero(&device_rec, sizeof(device_rec));
    device_rec.sll_ifindex = req.ifr_ifindex;
    return fd;
}

int readDateRec()
{
    int sd; // socket句柄
    int read_num;
    // 创建套接字
    sd = create_socket_handle(NET_INIT);
    if (sd < 0)
    {
        printf("socket error\n");
        return 0;
    }

    char buf[PACKET_LEN]; // data
    int len;

    memset(buf, 0, sizeof(buf)); // 刷新缓冲
    struct Read_data_rec *eth = (struct Read_data_rec *)buf;
    // 将字符数组 buf 转换为了 struct s_ethernet_header 类型的指针 eth
    // 直接通过 eth 指针来访问以太网帧中的各个字段
    // 接收数据
    while (1)
    {
        len = recvfrom(sd, buf, PACKET_LEN, 0, NULL, NULL);
        if (len < 0)
        {
            printf("recvfrom error, %d\n", errno);
            printf("\n");
        }
        else if (eth->head.type == 0x10 && ntohs(eth->head.ptcl_id) == 0xff01)
        {
            // 打印接收报文的MAC地址
            printf("版本：%02x\n", eth->head.version);
            printf("类型：%02x\n", eth->head.type);
            printf("源端口：%02x\n", eth->head.source_port);
            printf("保留：%02x\n", eth->head.reserve);
            printf("本地时间秒时间戳：%08x\n", ntohl(eth->head.local_time_sec));
            printf("本地时间纳秒时间戳：%08x\n", ntohl(eth->head.local_time_nanosec));
            printf("协议标识：%4x\n", ntohs(eth->head.ptcl_id));
            printf("帧标识：%4x\n", ntohs(eth->head.frame_id));
            printf("读数据量%4x\n", ntohs(eth->payload.data_n));
            printf("保留位%4x\n", ntohs(eth->payload.reserve));
            printf("读数据地址%08x\n", ntohl(eth->payload.addr));
            // printf("数据%d\n", ntohl(eth->payload.data));
            read_num = ntohs(eth->payload.data_n);
            for (int i = 0; i < read_num; i++)
            {
                printf("数据%d\n", ntohl(eth->payload.data[i]));
            }
            printf("\n");
        }
    }

    close(sd);
    return 0;
}

struct Pack_rec packRec()
{
    struct Pack_rec tsmp_pack;

    int sd; // socket句柄
    // 创建套接字
    sd = create_socket_handle(NET_INIT);
    if (sd < 0)
    {
        printf("socket error\n");
    }

    char buf[PACKET_LEN]; // data
    int len;

    memset(buf, 0, sizeof(buf)); // 刷新缓冲
    struct Pack_rec *eth = (struct Pack_rec *)buf;
    // 将字符数组 buf 转换为了 struct s_ethernet_header 类型的指针 eth
    // 直接通过 eth 指针来访问以太网帧中的各个字段
    // 接收数据
    len = recvfrom(sd, buf, PACKET_LEN, 0, NULL, NULL);
    if (len < 0)
    {
        printf("recvfrom error, %d\n", errno);
        printf("\n");
    }
    else if (ntohs(eth->head.ptcl_id) == 0xff01)
    {
        memcpy(&tsmp_pack.head, &eth->head, sizeof(struct Tsmp_rec_head));          // 打包头
        memcpy(&tsmp_pack.payload, &eth->payload, sizeof(struct Pack_rec_payload)); // 打包负载

        printf("版本：%02x\n", tsmp_pack.head.version); // 用于测试
    }
    close(sd);
    return tsmp_pack;
}

struct Resp_rec respRec()
{
    struct Resp_rec tsmp_pack;

    int sd; // socket句柄
    // 创建套接字
    sd = create_socket_handle(NET_INIT);
    if (sd < 0)
    {
        printf("socket error\n");
    }

    char buf[PACKET_LEN]; // data
    int len;

    memset(buf, 0, sizeof(buf)); // 刷新缓冲
    struct Resp_rec
        *eth = (struct Resp_rec *)buf;
    // 将字符数组 buf 转换为了 Resp_rec 类型的指针 eth
    // 直接通过 eth 指针来访问以太网帧中的各个字段
    // 接收数据
    len = recvfrom(sd, buf, PACKET_LEN, 0, NULL, NULL);
    if (len < 0)
    {
        printf("recvfrom error, %d\n", errno);
        printf("\n");
    }
    else if (ntohs(eth->head.ptcl_id) == 0xff01)
    {
        memcpy(&tsmp_pack.head, &eth->head, sizeof(struct Tsmp_rec_head));          // 打包head
        memcpy(&tsmp_pack.payload, &eth->payload, sizeof(struct Resp_rec_payload)); // 打包payload
        printf("版本：%02x\n", tsmp_pack.head.version);
    }

    close(sd);
    return tsmp_pack;
}
